package com.app.game.control;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;

import com.app.ThreadManager;
import com.app.game.chat.Message;
import com.app.game.other.Player;
import com.app.observers.ClientObserver;
import com.app.server.ClientHandler;
import com.app.task.Task;
import com.app.task.TaskWatcher;
import com.app.task.WaitingTask;

public class TcpHostGameController implements HostGameController,
		ClientObserver,TaskWatcher {

	private List<ClientHandler> clients = Collections
			.synchronizedList(new ArrayList<ClientHandler>());
	private ConcurrentHashMap<Integer, Player> playerList = new ConcurrentHashMap<Integer, Player>();
        private ConcurrentHashMap<Integer,Boolean> ready = new ConcurrentHashMap<Integer, Boolean>();
	//private LinkedBlockingQueue<Message> messages = new LinkedBlockingQueue<Message>();
	//private volatile int readyPlayers = 0;
	//private volatile int roundsDone = 0;
	//private volatile boolean gameover = false;
	private WaitingTask waitReadyTask = new WaitingTask(), waitRoundDoneTask = new WaitingTask();
	
	public TcpHostGameController(){
		waitReadyTask.addTaskWatcher(this);
		waitRoundDoneTask.addTaskWatcher(this);
	}
	
	@Override
	public void doSpin() {
		Random random = new Random();
		Integer result = random.nextInt(37);
		for (ClientHandler client : clients) {
			client.sendResult(result);
		}

	}

	@Override
	public void waitPlayersReady() {
		waitReadyTask.setTargetValue(clients.size());
		waitReadyTask.resetCurrentValue();
		ThreadManager.getInstance().execute(waitReadyTask);
	}

	@Override
	public void waitRoundDone() {
		waitRoundDoneTask.setTargetValue(playerList.size());
		ThreadManager.getInstance().execute(waitRoundDoneTask);
	}

	@Override
	public void startGame() {
		for (ClientHandler client : clients) {
			client.sendGameIsStarting();
		}
		//gameover = false;
		waitRoundDone();
	}

	@Override
	public void finishGame() {
		for (ClientHandler client : clients) {
			client.sendGameIsEnding();
		}
		waitReadyTask.stop();
		waitRoundDoneTask.stop();
	}

	@Override
	public void addClient(ClientHandler client) {
		client.registerObserver(this);
		clients.add(client);
		ThreadManager.getInstance().execute(client);
	}

	@Override
	public void updatePlayer(Player player, Integer id) {
		playerList.put(id, player);
                if(!ready.containsKey(id))
                ready.put(id, Boolean.FALSE);
		HashMap<Integer, Player> localList = new HashMap<Integer, Player>();
		Set<Entry<Integer, Player>> set = playerList.entrySet();
		Iterator<Entry<Integer, Player>> it = set.iterator();
		while (it.hasNext()) {
			Entry<Integer, Player> entry = it.next();
			localList.put(entry.getKey(), entry.getValue());
		}
		for (ClientHandler client : clients) {
			client.sendPlayerlist(localList);
		}
                Set s = ready.entrySet();
                Iterator i = s.iterator();
                while(i.hasNext()){
                    Entry<Integer,Boolean> entry  = (Entry<Integer,Boolean>) i.next();
                    if(entry.getValue()){
                        for(ClientHandler client: clients){
                            client.sendReadyNotification(entry.getKey());
                        }
                    }
                }
                waitReadyTask.stop();
                
                if(playerList.size() > 1){
                    waitReadyTask.setTargetValue(playerList.size());
                }else{
                    waitReadyTask.setTargetValue(1);
                }
                
                ThreadManager.getInstance().execute(waitReadyTask);
	}

	@Override
	public synchronized void updateMessage(Message msg) {
		
			//messages.offer(msg);
                        
			for (ClientHandler client : clients) {
				client.sendMessage(msg);
			}
		
	}

	@Override
	public void updateReady(Integer playerId) {
		//readyPlayers++;
                ready.put(playerId, Boolean.TRUE);
		waitReadyTask.incrementCurrentValue();
		for (ClientHandler client : clients) {
			client.sendReadyNotification(playerId);
		}

	}

	@Override
	public void updateRoundDone(Integer playerId) {
		//roundsDone++;
		waitRoundDoneTask.incrementCurrentValue();
		for (ClientHandler client : clients) {
			client.sendRoundDoneNotification(playerId);
		}

	}

	@Override
	public synchronized void taskComplete(Task task) {
		if(task==waitReadyTask){
			startGame();
		}else if(task==waitRoundDoneTask){
			doSpin();
			waitRoundDone();
		}
		
	}

}
